/*数据管理模块*/
#ifndef __MY_DATA__
#define __MY_DATA__
#include <unordered_map>
#include <pthread.h>
#include "util.hpp"
#include "config.hpp"

namespace cloud
{
    //文件信息结构体，备份的文件->形成文件信息结构体->存储
    typedef struct BackupInfo{
        bool pack_flag;//是否要压缩的标志
        size_t fsize;//文件大小
        time_t mtime;//最后一次修改时间
        time_t atime;//最后一次访问时间
        std::string real_path;//文件实际存储的路径
        std::string pack_path;//文件压缩包存储路径
        std::string url;

        //获取各项属性信息进行存储
        bool NewBackupInfo(const std::string& realpath)
        {
            FileUtil fu(realpath);
            if(fu.Exists() == false)
            {
                std::cout<<"new backupinfo: file not exists!\n";
                return false;
            }
            //利用FileUtil文件工具类，取获取文件的各种属性，然后填充到文件信息结构体中
            Config* config = Config::GetInstance();
            std::string packdir = config->GetPackDir();
            std::string packsuffix = config->GetPackFileSuffix();
            std::string download_prefix = config->GetDownloadPrefix();

            //./backdir/a.txt -> ./packdir/a.txt/lz
            this->pack_flag = false;//新增的文件，压缩标志肯定是false
            this->fsize = fu.FileSize();
            this->mtime = fu.LastMTime();
            this->atime = fu.LastATime();
            this->real_path = realpath;
            //压缩包路径+文件名称+文件后缀
            this->pack_path = packdir+fu.FileName()+packsuffix;
            //./backdir/a.txt -> download/a.txt
            this->url = download_prefix + fu.FileName();

            return true;
        }
    }BackupInfo;

    //数据管理者
    class DataManager
    {
    private:
        std::string _backup_file;//数据持久化存储文件
        pthread_rwlock_t _rwlock;//读写锁，读共享，锁互斥
        std::unordered_map<std::string,BackupInfo> _table;
    public:
        DataManager()
        {
            _backup_file = Config::GetInstance()->GetBackupFile();//获取持久化存储文件名
            pthread_rwlock_init(&_rwlock,NULL);//初始化读写锁
            InitLoad();
        }
        ~DataManager()
        {
            pthread_rwlock_destroy(&_rwlock);//销毁读写锁
        }
        bool Insert(const BackupInfo& info)
        {
            pthread_rwlock_wrlock(&_rwlock);
            _table[info.url] = info;
            pthread_rwlock_unlock(&_rwlock);
            Storage();//只要有插入的文件信息结构体，就进行一次持久化存储
            return true;
        }
        bool Update(const BackupInfo& info)
        {
            pthread_rwlock_wrlock(&_rwlock);
            _table[info.url] = info;
            pthread_rwlock_unlock(&_rwlock);
            Storage();
            return true;
        }
        
        bool GetOneByURL(const std::string &url, BackupInfo *info) 
        {
			pthread_rwlock_wrlock(&_rwlock);
			//因为url是key值，所以直接通过find进行查找
			auto it = _table.find(url);
			if (it == _table.end()) {
				pthread_rwlock_unlock(&_rwlock);
				return false;
			}
			*info = it->second;
			pthread_rwlock_unlock(&_rwlock);
			return true;
		}
        bool GetOneByRealPath(const std::string &realpath, BackupInfo *info) 
        {
				pthread_rwlock_wrlock(&_rwlock);
				auto it = _table.begin();
				for (; it != _table.end(); ++it){
					if (it->second.real_path == realpath) {
						*info = it->second;
						pthread_rwlock_unlock(&_rwlock);
						return true;
					}
				}
				pthread_rwlock_unlock(&_rwlock);
				return false;
		}
        //获取所有文件信息到arry数组中
        bool GetAll(std::vector<BackupInfo>* arry)
        {
            pthread_rwlock_wrlock(&_rwlock);
            auto it = _table.begin();
            for(;it!=_table.end();++it)
            {
                arry->push_back(it->second);
            }
            pthread_rwlock_unlock(&_rwlock);
            return true;
        }
        //每次数据新增或者修改都需要重新持久化存储，避免数据丢失
        bool Storage()
        {
            //1.获取所有数据
            std::vector<BackupInfo> arry;
            this->GetAll(&arry);
            //2.添加到Json::Value
            Json::Value root;
            for(int i=0;i<arry.size();i++)
            {
                Json::Value item;
                item["pack_flag"] = arry[i].pack_flag;
                item["fsize"] = (Json::Int64)arry[i].fsize;
                item["atime"] = (Json::Int64)arry[i].atime;
                item["mtime"] = (Json::Int64)arry[i].mtime;
                item["real_path"] = arry[i].real_path;
                item["pack_path"] = arry[i].pack_path;
                item["url"] = arry[i].url;
                root.append(item);//添加数组元素
            }
            //3.对Json::Value进行序列化
            std::string body;
            JsonUtil::Serialize(root,&body);
            //4.写文件
            FileUtil fu(_backup_file);
            fu.SetContent(body);
            return true;
        }
        //初始化加载文件，每次服务器重启都要加载持久化的文件信息到哈希表中（内存中）
        bool InitLoad()
        {
            //1.将持久化存储文件中的文件信息（字符串）读取出来，先存到body里面
            FileUtil fu(_backup_file);
            if(fu.Exists() == false)
            {
                return true;
            }
            std::string body;
            fu.GetContent(&body);

            //2.将文件信息（字符串）反序列化
            Json::Value root;
            JsonUtil::UnSerialize(body,&root);
            //3.将反序列化得到的Json::Value中的数据添加到table中
            for(int i=0; i < root.size(); i++)
            {
                //将反序列化后的持久化存储的文件信息，放到BackupInfo文件信息管理结构体中
                BackupInfo info;
                info.pack_flag = root[i]["pack_flag"].asBool();
                info.fsize = root[i]["fsize"].asInt64();
                info.atime = root[i]["atime"].asInt64();
                info.mtime = root[i]["mtime"].asInt64();
                info.pack_path = root[i]["pack_path"].asString();
                info.real_path = root[i]["real_path"].asString();
                info.url = root[i]["url"].asString();
                //然后插入哈希表
                Insert(info);
            }
            return true;
        }
    };

}
#endif
